package com.vast.ui.component.socketinterface.serverblocking;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.Executor;

import org.eclipse.core.runtime.ListenerList;

import com.vast.ui.component.socketinterface.listner.IReceiveListener;
import com.vast.ui.component.socketinterface.listner.ISocketConnectionListener;
import com.vast.ui.component.socketinterface.protocol.VaSTUIComponentProtocol;
import com.vast.ui.component.socketinterface.request.Request;
import com.vast.ui.component.socketinterface.request.RequestQueue;
import com.vast.ui.component.socketinterface.servercommon.IServer;
import com.vast.ui.component.util.ConsoleLoggerSingleton;
import com.vast.ui.component.util.Logger;

public class BlockingServer implements IServer {
	public int          serverRecvPort;
	public int          serverSendPort;
	private final  ListenerList receiveListenerList;
	private final  ListenerList socketConnectionListenerList;
	private ServerSocket serverRecvSocket;
	private ServerSocket serverSendSocket;
	private Socket       clientRecvSocket;
	private Socket       clientSendSocket;
	private RequestQueue sendRequestQueue;
	private DataInputStream     in;
	private BufferedOutputStream out;
	private final Executor executor;
	private  final Logger   logger;
	
	public BlockingServer (int serverPort, RequestQueue sendRequestQueue, Executor executor) {
		this.serverRecvPort   = serverPort;
		this.serverSendPort   = serverPort + 1;
		this.sendRequestQueue = sendRequestQueue;
		this.executor         = executor;
		this.logger           = ConsoleLoggerSingleton.getInstance();
		this.receiveListenerList = new ListenerList();
		this.socketConnectionListenerList = new ListenerList();
	}
	
	public void send(Request request) {
		sendRequestQueue.putRequest(request);
	}
	
	public void closeConnection() {
		// TODO Auto-generated method stub
		
		
			if(!clientRecvSocket.isClosed()) {
				try {
					in.close();
					clientRecvSocket.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		
		if(!clientSendSocket.isClosed()) {
				try {
					out.close();
					clientSendSocket.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		
		try {
			serverRecvSocket.close();
			serverSendSocket.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void addSocketConnectionListener(ISocketConnectionListener listener){
		socketConnectionListenerList.add(listener);
	}
	
	public void removeSocketConnectionListener(ISocketConnectionListener listener){
		socketConnectionListenerList.remove(listener);
	}
	
	public void addReceiveListener(IReceiveListener listener){
		receiveListenerList.add(listener);
	}
	
	public void removeReceiveListener(IReceiveListener listener){
		receiveListenerList.remove(listener);
	}
	
	public void serverRecvThread() {
		logger.writeEntry("Start serverRecvThread()");
		try {
			logger.writeEntry("Waiting for client Connection (port :" + serverRecvPort + ")");
			clientRecvSocket = serverRecvSocket.accept();
			in = new DataInputStream(new BufferedInputStream(clientRecvSocket.getInputStream()));
			while(true) {
				Short sizeOfData = in.readShort();
				Request request  = new Request(sizeOfData);
				request.writeShort(sizeOfData);
				in.read(request.data, 2, sizeOfData - 2);
				
				Short command = (short) ((request.data[2] << 8) + (request.data[3] << 0));
				if (command == VaSTUIComponentProtocol.PK_SOCKET_TERMINATE) {
					return;
				}
				Object[] listeners = receiveListenerList.getListeners();
				for (Object listener : listeners) {
					((IReceiveListener) listener).received(request);
				}
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			Object[] listeners = socketConnectionListenerList.getListeners();
			for (Object listener : listeners) {
				((ISocketConnectionListener) listener).closeConnection();
			};
		}
	}
	
	public void serverSendThread() {
		logger.writeEntry("Start serverSendThread()");
		try {
			logger.writeEntry("Waiting for client Connection (port :" + serverSendPort + ")");
			clientSendSocket = serverSendSocket.accept();
			out = new BufferedOutputStream(clientSendSocket.getOutputStream());
			while(true) {
				Request request  = sendRequestQueue.getRequest();
				out.write(request.data);
				out.flush();
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void openConnection() {
		// TODO Auto-generated method stub
		logger.writeEntry("Open Connection");	
		
		try {
			serverRecvSocket = new ServerSocket(serverRecvPort);
			serverSendSocket = new ServerSocket(serverSendPort);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		executor.execute(
				new Runnable() {
					public void run() {
						serverRecvThread();
					}
				}
			);
		
		executor.execute(
				new Runnable() {
					public void run() {
						serverSendThread();
					}
				}
			);
	}
}
